#include "pch.h"
#include "ShadowRenderer.h"
#include "ShadowMap.h"

namespace mini
{
	CShadowRenderer::CShadowRenderer(CDevice* pDevice)
		: CRenderer(pDevice)
	{
		mOrder = 245;
		mRenderTypeFlag = RendererType::ShadowRenderer;
	}

	CShadowRenderer::~CShadowRenderer()
	{
		SafeRelease(mpShadow);
	}

	void CShadowRenderer::setShadowType(shadowType type)
	{
		if (nullptr != mpShadow)
		{
			if (mpShadow->getType() != type)
			{
				SafeDelete(mpShadow);
			}
			else
			{
				return;
			}
		}

		switch (type)
		{
		case mini::shadowType::Shadowmap:
		{
			mpShadow = new CShadowMap();
		}
		break;
		default:
			assert(false);
			break;
		}

	}

	void CShadowRenderer::setEffect(CShadow* pShadow)
	{
		if (nullptr != pShadow && pShadow != mpShadow)
		{
			SafeRelease(mpShadow);
			mpShadow = pShadow;
			mpShadow->AddRef();
		}
	}

	void CShadowRenderer::commitToGpu()
	{
		if (nullptr != mpShadow)
		{
			for (auto item : mLightActors)
			{
				mpShadow->setLight(item);
				int nPass = mpShadow->nPassCount();
				for (int i = 0; i < nPass; ++i)
				{
					auto* pShaderUnit = mpShadow->passBegin(mpDeferredContext, i);
					if (nullptr != pShaderUnit)
					{
						for (auto& item : mZbufferOffRenderUnits)
						{
							auto _item = (item.second);
							mpShadow->updateMeshMatrix(pShaderUnit, &(_item.second)->getMatrix());
							pShaderUnit->apply(mpDeferredContext);
							(_item.second)->render(mpDeferredContext);
						}

						for (auto& item : mRenderUnits)
						{
							for (auto& child : (item.second))
							{
								mpShadow->updateMeshMatrix(pShaderUnit, &child->getMatrix());
								pShaderUnit->apply(mpDeferredContext);
								child->render(mpDeferredContext);
							}
						}
						for (auto& item : mAlphaRenderUnits)
						{
							for (auto& child : (item.second))
							{
								mpShadow->updateMeshMatrix(pShaderUnit, &child->getMatrix());
								pShaderUnit->apply(mpDeferredContext);
								child->render(mpDeferredContext);
							}
						}
					}
					mpShadow->passEnd(mpDeferredContext, i);
				}
			}
		}
	}

	void CShadowRenderer::addUnit(CUnit* pUnit, CMaterialUnit* pMaterialUnit, EntityType Type, INT32 zLayer)
	{
		if (pMaterialUnit->isShadow())
		{
			CRenderer::addUnit(pUnit, pMaterialUnit, Type, zLayer);
		}
	}

}
